/*
 *    Copyright (c) 2018-2025, nart All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: nart
 */
package com.nai365.nart.operation.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nai365.nart.blockchain.dto.TransferDto;
import com.nai365.nart.common.core.util.R;
import com.nai365.nart.common.security.util.SecurityUtils;
import com.nai365.nart.member.entity.Member;
import com.nai365.nart.member.feign.RemoteMemberService;
import com.nai365.nart.operation.config.RabbitmqConfig;
import com.nai365.nart.operation.dto.CompoundDto;
import com.nai365.nart.operation.entity.CompoundDemand;
import com.nai365.nart.operation.entity.CompoundRecord;
import com.nai365.nart.operation.entity.CompoundRecordDetail;
import com.nai365.nart.operation.entity.CompoundResources;
import com.nai365.nart.operation.mapper.CompoundDemandMapper;
import com.nai365.nart.operation.mapper.CompoundRecordDetailMapper;
import com.nai365.nart.operation.mapper.CompoundRecordMapper;
import com.nai365.nart.operation.service.CompoundDemandService;
import com.nai365.nart.operation.service.CompoundRecordService;
import com.nai365.nart.operation.service.ProductService;
import com.nai365.nart.product.entity.SkuInfo;
import lombok.AllArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.autoconfigure.klock.annotation.Klock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 合成记录
 *
 * @author baogs
 * @date 2022-07-01 11:13:17
 */
@Service
@AllArgsConstructor
public class CompoundRecordServiceImpl extends ServiceImpl<CompoundRecordMapper, CompoundRecord> implements CompoundRecordService {

	private final CompoundDemandMapper compoundDemandMapper;

	private final ProductService productService;

	private final CompoundRecordDetailMapper compoundRecordDetailMapper;

	private final CompoundDemandService compoundDemandService;

	private final RabbitTemplate rabbitTemplate;

	private final RemoteMemberService remoteMemberService;


	@Override
	@Transactional(rollbackFor = Exception.class)
	@Klock()
	public CompoundRecord compound(CompoundDto compoundDto) throws Exception {
		//验证合成材料
		CompoundDemand demand = compoundDemandMapper.selectById(compoundDto.getCompoundDemandId());
		LocalDateTime now = LocalDateTime.now();
		if (now.isBefore(demand.getBeginTime())) {
			throw new Exception("合成活动还未开始！");
		}
		if (now.isAfter(demand.getEndTime())) {
			throw new Exception("合成活动已结束！");
		}
		if (demand.getActualAmount() >= demand.getPlantAmount()) {
			throw new Exception("你慢人一步，合成结束!");
		}
		if (compoundDto.getSkuIdList() == null || compoundDto.getSkuIdList().isEmpty()) {
			throw new Exception("合成所需材料不能为空!");
		}
		List<CompoundResources> resourcesList = compoundDemandService.findResourcesByDemand(compoundDto.getCompoundDemandId());
		Map<Long, CompoundResources> compoundResourcesHashMap = new HashMap<>();
		int count = 0;
		for (CompoundResources resources : resourcesList) {
			count += resources.getCopies();
			compoundResourcesHashMap.put(resources.getSpuId(), resources);
		}
		if (compoundDto.getSkuIdList().size() < count) {
			throw new Exception("合成所需材料不足!");
		}
		Map<Long, List<SkuInfo>> resourcesMap = new HashMap<>();
		List<SkuInfo> skuInfoList = this.productService.findSkuByIds(compoundDto.getSkuIdList());
		for (SkuInfo sku : skuInfoList) {
			if (!Objects.equals(sku.getOwnerId(), SecurityUtils.getUser().getId())) {
				throw new Exception("你所提交的藏品中有不属于你的藏品!");
			}
			if (sku.getPublishStatus() != 0) {
				throw new Exception("你所提交的藏品中有不能合成的藏品!");
			}
			if (resourcesMap.get(sku.getSpuId()) != null) {
				resourcesMap.get(sku.getSpuId()).add(sku);
			} else {
				resourcesMap.put(sku.getSpuId(), new ArrayList<>());
				resourcesMap.get(sku.getSpuId()).add(sku);
			}
		}
		for (CompoundResources resources : resourcesList) {
			if (resourcesMap.get(resources.getSpuId()) != null && resources.getCopies() != resourcesMap.get(resources.getSpuId()).size()) {
				throw new Exception("你所提交的藏品不匹配!");
			}
		}
		//开始合成
		SkuInfo targetSku = productService.lockSkuInfo(demand.getTargetSpuId());
		CompoundRecord record = new CompoundRecord();
		try {
			record.setCompoundDemandId(demand.getId());
			record.setUserId(SecurityUtils.getUser().getId());
			record.setStatus(0);
			record.setTargetSkuId(targetSku.getSkuId());
			record.setTargetSkuName(targetSku.getSkuName());
			record.setTargetSkuToken(targetSku.getToken() + "");
			record.setTargetSkuImage(demand.getTargetSpuImage());
			record.setTargetSkuCode(targetSku.getSkuCode());
			super.save(record);
			List<CompoundRecordDetail> detailList = new ArrayList<>();
			for (SkuInfo sku : skuInfoList) {
				CompoundRecordDetail detail = new CompoundRecordDetail();
				detail.setCompoundDemandId(demand.getId());
				detail.setCompoundRecordId(record.getId());
				detail.setSpuId(demand.getTargetSpuId());
				detail.setSkuId(sku.getSkuId());
				detail.setSkuName(sku.getSkuName());
				detail.setSkuToken(sku.getToken() + "");
				//处理图片
				if (StringUtils.isBlank(sku.getSkuDefaultImg())) {
					CompoundResources compoundResources = compoundResourcesHashMap.get(sku.getSpuId());
					if (compoundResources != null) {
						detail.setSkuImage(compoundResources.getSpuImage());
					}
				} else {
					detail.setSkuImage(sku.getSkuDefaultImg());
				}
				detail.setSkuCode(sku.getSkuCode());
				compoundRecordDetailMapper.insert(detail);
				sku.setPublishStatus(4);
				productService.updateSku(sku);
				detailList.add(detail);
				//回收藏品
				TransferDto transferDto = TransferDto.builder()
						.from(sku.getOwnerAddress())
						.to("0x49cb0e9a80887e89255e005fc7919b598f5b0851")
						.copies(1)
						.token(sku.getToken() + "")
						.notifyRoute(RabbitmqConfig.COMPOUND_ROUTING_KEY)
						.exchangeName(RabbitmqConfig.BLOCKCHAIN_EXCHANGE)
						.requestId("detail-" + detail.getId())
						.build();
				rabbitTemplate.convertAndSend(RabbitmqConfig.BLOCKCHAIN_EXCHANGE, RabbitmqConfig.TRANSFER_ROUTING_KEY, transferDto);
			}
			record.setDetailList(detailList);
		} catch (Exception e) {
			productService.lockSkuInfo(demand.getTargetSpuId());
			throw e;
		}
		demand.setActualAmount(demand.getActualAmount() + 1);
		compoundDemandMapper.updateById(demand);

		Member member = getById(SecurityUtils.getUser().getId());

		TransferDto transferDto = TransferDto.builder()
				.from("0xb96a0b55052c5d081eed749161b1dc2176b5a61f")
				.to(member.getOpbChainClientAddress())
				.copies(1)
				.token(targetSku.getToken() + "")
				.exchangeName(RabbitmqConfig.BLOCKCHAIN_EXCHANGE)
				.notifyRoute(RabbitmqConfig.COMPOUND_ROUTING_KEY)
				.requestId("record-" + record.getId())
				.build();
		rabbitTemplate.convertAndSend(RabbitmqConfig.BLOCKCHAIN_EXCHANGE, RabbitmqConfig.TRANSFER_ROUTING_KEY, transferDto);

		return record;
	}

	@Override
	public CompoundRecord getById(Serializable id) {
		CompoundRecord result = super.getById(id);
		LambdaQueryWrapper<CompoundRecordDetail> queryWrapper = Wrappers.lambdaQuery();
		queryWrapper.eq(CompoundRecordDetail::getCompoundRecordId, result.getId());
		List<CompoundRecordDetail> detailList = compoundRecordDetailMapper.selectList(queryWrapper);
		result.setDetailList(detailList);
		return result;
	}

	private Member getById(Long id) throws Exception {
		R<Member> remote = remoteMemberService.getById(id);
		if (remote.getCode() == 0 && remote.getData() != null) {
			return remote.getData();
		}
		throw new Exception(remote.getMsg());
	}
}
